
#include "JsonClientServer.h"
#include "Types.h"
#include "json.h"
#include "ClientIOManager.h"
#include <winsock2.h>
#include <boost/shared_ptr.hpp>
 
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wsock32.lib")

bool sendCommand(std::string ip,std::string port, std::string  command)
{
	
	int iport = atoi(port.c_str()); 
	 

	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 0);
	if (0 != WSAStartup(sockVersion, &wsaData))
	{
		std::cout << "Failed to retrive socket version." 
			<< std::endl;
		return false;
	}

	SOCKET sock_client;
	sock_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sock_client)
	{
		std::cout << "Invalid socket." << std::endl;
		WSACleanup();
		return false; 
	}
	sockaddr_in addr_sev;
	addr_sev.sin_family = AF_INET;
	addr_sev.sin_port = htons(iport);
	addr_sev.sin_addr.s_addr = inet_addr("127.0.0.1");
	if (SOCKET_ERROR == connect(sock_client, (sockaddr *)&addr_sev, sizeof(addr_sev)))
	{
		std::cout << "Failed to connect." << std::endl;
		WSACleanup();
		return false;
	}

	char * buffer = new char[2000];
	assert(command.length()<=2000);
	strcpy(buffer,command.c_str());


	int send_size = send(sock_client,buffer,strlen(buffer)+1,0);
	delete[]buffer;
	if(send_size<0)
	{
		std::cout<<"failed"<<std::endl;
		closesocket(sock_client);
		WSACleanup();
		return false; 
	}
	 

	bool bl = false;
	char buf[1];
	memset(buf, 0, sizeof(buf));
	int recv_size = 0;
	recv_size = recv(sock_client, buf, 512, 0);
	if (recv_size==1)
	{
		 bl = *(bool*)buf;
	}
	else
	{
		std::cout << "receive data is overflow" << std::endl;
	}

	closesocket(sock_client);
	

	return bl;
}


JsonClientServer* JsonClientServer::jsonClientServer = NULL;
JsonClientServer::JsonClientServer(void)
{
}


JsonClientServer::~JsonClientServer(void)
{
}
JsonClientServer* JsonClientServer::getInstance()
{
	if(jsonClientServer==NULL)
	{
		jsonClientServer = new JsonClientServer();
	}
	return jsonClientServer;
}
void JsonClientServer::initial()
{
	ClientIOManager::getInstance();
}
// a block connect to test if the server is available
bool JsonClientServer::connectServer(std::string serverIp, std::string serverPort)
{
	this->serverIp = serverIp;
	this->serverPort = serverPort;
	int iport = atoi(serverPort.c_str()); 


	SOCKET sock_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sock_client)
	{
		std::cout << "Invalid socket." << std::endl;
		return false; 
	}
	sockaddr_in addr_sev;
	addr_sev.sin_family = AF_INET;
	addr_sev.sin_port = htons(iport);
	addr_sev.sin_addr.s_addr = inet_addr("127.0.0.1");
	if (SOCKET_ERROR == connect( sock_client, (sockaddr *)&addr_sev, sizeof(addr_sev)))
	{
		std::cout << "Failed to connect." << std::endl;
		return false;
	}
	closesocket(sock_client);
	return true;

}
 
bool JsonClientServer::registerQuery(std::string query,  void (*callBackFunction)(Element& element) )
{
	//create client socket input to get data from server by socket, the schema information is used to check input
	ClientIOManager::getInstance()->addStreamInput(CLIENT_IP,CLIENT_PORT,callBackFunction);
	 
	

	
	//generate register query command
	Document& queryDocuemnt = fromjson(query);
	DocumentBuilder registerQueryCommandbuilder;
	registerQueryCommandbuilder.append("command_type","register_query");
	registerQueryCommandbuilder.appendObject("query_content",queryDocuemnt.objdata(),queryDocuemnt.objsize());
	DocumentBuilder outputSpecificationBuilder;
	outputSpecificationBuilder.append("output_type","socket_output");
	outputSpecificationBuilder.append("output_ip",CLIENT_IP);
	outputSpecificationBuilder.append("output_port",CLIENT_PORT);
	Document& outputSpecificationDocument = outputSpecificationBuilder.obj();
	registerQueryCommandbuilder.appendObject("output_specification",outputSpecificationDocument.objdata(),outputSpecificationDocument.objsize());
	Document& registerQueryCommandDocument = registerQueryCommandbuilder.obj();
	std::string registerQueryCommandString = registerQueryCommandDocument.toString();
	//std::cout<<registerQueryCommandString<<std::endl;
	//register query on server 
	bool bl = sendCommand(serverIp,serverPort,registerQueryCommandString);
	return bl;
}
void JsonClientServer::execute(void)
{
	
	ClientIOManager::getInstance()->execute();
		
	
}